/* contrib/cube/cubedata.h */

/*
 * 这个限制相当任意，但不要设置得太大，以免在大小计算中导致溢出。
 */
#define CUBE_MAX_DIM (100)

typedef struct NDBOX
{
	/* varlena 头部（请勿直接触摸！） */
	int32		vl_len_;

	/*----------
	 * 头部包含有关 NDBOX 的信息。为了与旧版本的二进制兼容，它被定义为“unsigned int”。
	 *
	 * 存储以下信息：
	 *
	 *	bits 0-7  : 立方体维度的数量；
	 *	bits 8-30 : 未使用，初始化为零；
	 *	bit  31   : 点标志。如果设置，则不存储右上坐标，这些坐标隐含与左下坐标相同。
	 *----------
	 */
	unsigned int header;

	/*
	 * 每个维度的左下坐标首先出现，接着是右上坐标，除非点标志被设置。
	 */
	double		x[FLEXIBLE_ARRAY_MEMBER];
} NDBOX;

/* NDBOX 访问宏 */
#define POINT_BIT			0x80000000
#define DIM_MASK			0x7fffffff

#define IS_POINT(cube)		( ((cube)->header & POINT_BIT) != 0 )
#define SET_POINT_BIT(cube) ( (cube)->header |= POINT_BIT )
#define DIM(cube)			( (cube)->header & DIM_MASK )
#define SET_DIM(cube, _dim) ( (cube)->header = ((cube)->header & ~DIM_MASK) | (_dim) )

#define LL_COORD(cube, i) ( (cube)->x[i] )
#define UR_COORD(cube, i) ( IS_POINT(cube) ? (cube)->x[i] : (cube)->x[(i) + DIM(cube)] )

#define POINT_SIZE(_dim)	(offsetof(NDBOX, x) + sizeof(double)*(_dim))
#define CUBE_SIZE(_dim)		(offsetof(NDBOX, x) + sizeof(double)*(_dim)*2)

/* fmgr 接口宏 */
#define DatumGetNDBOXP(x)	((NDBOX *) PG_DETOAST_DATUM(x))
#define PG_GETARG_NDBOX_P(x)	DatumGetNDBOXP(PG_GETARG_DATUM(x))
#define PG_RETURN_NDBOX_P(x)	PG_RETURN_POINTER(x)

/* GiST 操作符策略编号 */
#define CubeKNNDistanceCoord			15	/* ~> */
#define CubeKNNDistanceTaxicab			16	/* <#> */
#define CubeKNNDistanceEuclid			17	/* <-> */
#define CubeKNNDistanceChebyshev		18	/* <=> */

/* in cubescan.l */
extern int	cube_yylex(void);
extern void cube_yyerror(NDBOX **result, const char *message) pg_attribute_noreturn();
extern void cube_scanner_init(const char *str);
extern void cube_scanner_finish(void);

/* in cubeparse.y */
extern int	cube_yyparse(NDBOX **result);
